package com.parse;

import com.lex.Lexer;
import com.lex.Token;
import com.lex.TokenStream;
import com.lex.TokenType;
import com.parse.ast.*;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;


/**
 * 递归下降分析法生成抽象语法树AST
 */

@Slf4j
public class Parser {
    private final TokenStream tokens;
    private int position = 0;

    public static void main(String[] args) {
        File file = new File("target/classes/ast/tsa/D.java");
        String input = null;
        try {
            input = new String(Files.readAllBytes(Paths.get(file.getPath())));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        Lexer lexer = new Lexer(input);

        Token token = null;
        try {
            token = lexer.getNextToken();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        while (token != null && token.getType() != TokenType.EOF) {
            log.debug(token.toString());
            try {
                token = lexer.getNextToken();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        List<Token> tokenList = lexer.getTokenList();
        TokenStream tokenStream = new TokenStream(tokenList);
        Parser parser = new Parser(tokenStream);
        try {
            parser.parse();
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    public Parser(TokenStream tokens) {
        this.tokens = tokens;
    }

    /**
     * 注释
     * package
     * 注释
     * import
     * 注释
     * types
     *
     * @return
     */
    public ASTNode parse() throws ParseException {
        ASTNode compilationUnit = new ASTNode(ASTNodeType.COMPILATION_UNIT);

        // 解析 package 声明
        if (tokens.getCurrentToken(compilationUnit).getType() == TokenType.PACKAGE) {
            ASTNode packageDeclaration = parsePackageDeclaration();
            compilationUnit.addChild(packageDeclaration);
        }

        // 解析 import 语句
        while (tokens.getCurrentToken(compilationUnit).getType() == TokenType.IMPORT) {
            ASTNode importDeclaration = parseImportDeclaration();
            compilationUnit.addChild(importDeclaration);
        }

        // 解析声明
        if (tokens.getCurrentToken(compilationUnit).getType() != TokenType.EOF) {
            ASTNode classDeclaration = parseTypesDeclaration();
            compilationUnit.addChild(classDeclaration);
        }
        return compilationUnit;
    }

    /**
     * 接口
     * 枚举
     * 类
     *
     * @return
     */
    private ASTNode parseTypesDeclaration() throws ParseException {
        DeclarationTypesASTNode declarationTypesASTNode = new DeclarationTypesASTNode(ASTNodeType.TYPE_DECLARATION);

        while (tokens.getCurrentToken(declarationTypesASTNode).getType() != TokenType.EOF) {
            //处理类型修饰符
            Modify modify;
            boolean isAbstract = false;
            if (tokens.getCurrentToken(declarationTypesASTNode).getType() == TokenType.PUBLIC) {
                modify = new Modify(Modify.ModifyType.PUBLIC);
                consumeToken(TokenType.PUBLIC);
            } else if (tokens.getCurrentToken(declarationTypesASTNode).getType() == TokenType.PRIVATE) {
                modify = new Modify(Modify.ModifyType.PRIVATE);
                consumeToken(TokenType.PRIVATE);
            } else if (tokens.getCurrentToken(declarationTypesASTNode).getType() == TokenType.PROTECTED) {
                modify = new Modify(Modify.ModifyType.PROTECTED);
                consumeToken(TokenType.PROTECTED);
            } else {
                modify = new Modify(Modify.ModifyType.DEFAULT);
            }

            if (tokens.getCurrentToken(declarationTypesASTNode).getType() == TokenType.ABSTRACT) {
                consumeToken(TokenType.ABSTRACT);
                isAbstract = true;
            }

            if (tokens.getCurrentToken(declarationTypesASTNode).getType() == TokenType.CLASS) {
                consumeToken(TokenType.CLASS);
                Token nextToken = tokens.getCurrentToken(declarationTypesASTNode);
                if (nextToken.getType() == TokenType.IDENTIFIER) {
                    consumeToken(TokenType.IDENTIFIER);
                    ASTNode classDeclarationASTNode = parseClassDeclaration(
                            modify,
                            isAbstract,
                            declarationTypesASTNode,
                            nextToken);
                    declarationTypesASTNode.addChild(classDeclarationASTNode);
                } else {
                    throw new ParseException("Expecting '=' after identifier, but got " + nextToken.getValue());
                }
            } else if (tokens.getCurrentToken(declarationTypesASTNode).getType() == TokenType.INTERFACE) {
                consumeToken(TokenType.INTERFACE);
            } else if (tokens.getCurrentToken(declarationTypesASTNode).getType() == TokenType.ENUM) {
                consumeToken(TokenType.ENUM);
            }
        }
        return declarationTypesASTNode;
    }

    /**
     * 类成员变量
     * 属性
     * 方法
     * 内部类
     *
     * @param modify
     * @param isAbstract
     * @param parent
     * @param token
     * @return
     * @throws ParseException
     */
    private ASTNode parseClassDeclaration(Modify modify, boolean isAbstract, ASTNode parent, Token token) throws ParseException {
        ClassDeclarationASTNode classDeclaration = new ClassDeclarationASTNode(
                ASTNodeType.CLASS_DECLARATION,
                modify,
                isAbstract,
                parent,
                token);
        // 处理extends
        if (tokens.getCurrentToken().getType() == TokenType.EXTENDS) {
            consumeToken(TokenType.EXTENDS); // 匹配extends关键字
            if (tokens.getCurrentToken(classDeclaration).getType() == TokenType.IDENTIFIER) {
                classDeclaration.setSuperClassDeclarationASTNode(null);//后面装填
                classDeclaration.setSuperClassFullName(tokens.getCurrentToken().getValue());
                consumeToken(TokenType.IDENTIFIER); // 匹配父类名
            }
        }
        consumeToken(TokenType.LEFT_BRACE); // 匹配左花括号

        while (true) {
            if (tokens.getCurrentToken(classDeclaration).getType() == TokenType.RIGHT_BRACE) {
                consumeToken(TokenType.RIGHT_BRACE); // 匹配右花括号
                break;
            } else {
                if (tokens.getCurrentToken(classDeclaration).getType() == TokenType.PUBLIC) {
                    // 解析公有成员变量或方法
                    parseAllModifyMemberDeclaration(new Modify(Modify.ModifyType.PUBLIC), classDeclaration);
                } else if (tokens.getCurrentToken(classDeclaration).getType() == TokenType.PRIVATE) {
                    // 解析私有成员变量或方法
                    parseAllModifyMemberDeclaration(new Modify(Modify.ModifyType.PRIVATE), classDeclaration);
                } else if (tokens.getCurrentToken(classDeclaration).getType() == TokenType.PROTECTED) {
                    // 解析保护成员变量或方法
                    parseAllModifyMemberDeclaration(new Modify(Modify.ModifyType.PROTECTED), classDeclaration);
                } else {
                    // 无法识别的类成员
                    throw new ParseException("Unexpected token: " + tokens.getCurrentToken().getValue());
                }
            }
        }
        return classDeclaration;
    }

    /**
     *
     * @param modify 修饰符
     * @param classDeclarationASTNode
     * @throws ParseException
     */
    private void parseAllModifyMemberDeclaration(Modify modify, ClassDeclarationASTNode classDeclarationASTNode) throws ParseException {
        ASTNode publicMemberNode = null;
        consumeToken(modify.getModifyTokenType());//private public protected
        // 解析变量类型
        ASTNode typeNode = parseType();
        // 解析属性名字 或者是方法名
        Token currentFiledOrMethodToken = tokens.getCurrentToken(classDeclarationASTNode);
        if (currentFiledOrMethodToken.getType().equals(TokenType.IDENTIFIER)) {
            // 判断是否为方法
            if (tokens.catNextTokenNoComments().getType() == TokenType.LEFT_PAREN) {
                // 解析方法
                ASTNode methodNode = parseMethodDeclaration(classDeclarationASTNode, modify, typeNode);
                classDeclarationASTNode.addChild(methodNode);
            } else {
                // 解析属性声明
                ASTNode fieldNode = parseFieldDeclaration(classDeclarationASTNode, modify, typeNode);
                classDeclarationASTNode.addChild(fieldNode);
            }
        } else {
            throw new ParseException("Unexpected token: " + currentFiledOrMethodToken.getValue());
        }
    }


    private ASTNode parseFieldDeclaration(ClassDeclarationASTNode classDeclarationASTNode, Modify modify, ASTNode typeNode) throws ParseException {
        FieldDeclarationASTNode fieldDeclarationNode = new FieldDeclarationASTNode(ASTNodeType.FIELD_DECLARATION, tokens.getCurrentToken(classDeclarationASTNode), classDeclarationASTNode);
        fieldDeclarationNode.setModify(modify);
        fieldDeclarationNode.addChild(typeNode);
        // 处理当前字段声明中的所有字段
        while (true) {
            Token token = tokens.getCurrentToken(classDeclarationASTNode);
            // 处理字段名
            if (token.getType() == TokenType.IDENTIFIER) {
                VariableASTNode variableNode = new VariableASTNode(ASTNodeType.VARIABLE);
                variableNode.setVariableType(VariableASTNode.VariableType.FIELD);
                variableNode.setVariableName(token.getValue());
                variableNode.setVariableDataType(typeNode);

                // 生成变量声明语句节点并添加到AST树上
                fieldDeclarationNode.addChild(variableNode);
                consumeToken(TokenType.IDENTIFIER);
                // 检查是否是静态字段
                if (this.tokens.getCurrentToken(fieldDeclarationNode).getType() == TokenType.EQUAL) {
                    // 静态字段声明
                    consumeToken(TokenType.EQUAL);
//                    ASTNode valueNode = parseExpression(fieldDeclarationNode,variableNode,TokenType.EQUAL);
                    ASTNode valueNode = parseInitialExpression(fieldDeclarationNode, variableNode);
                    fieldDeclarationNode.setVaribleInitialer(valueNode);
                    fieldDeclarationNode.addChild(valueNode);
                    variableNode.setVariableValue(valueNode);
                }

                // 处理分号
                Token currentToken = this.tokens.getCurrentToken(fieldDeclarationNode);
                if (currentToken.getType() == TokenType.SEMICOLON) {
                    consumeToken(TokenType.SEMICOLON);
                    break;
                } else if (currentToken.getType() == TokenType.COMMA) {
                    consumeToken(TokenType.COMMA);
                    continue;
                } else {
                    throw new ParseException("Expected ';' or ',' in field declaration, but got " + currentToken.getValue());
                }
            } else {
                throw new ParseException("Expected identifier in field declaration, but got " + token.getValue());
            }
        }

        return fieldDeclarationNode;
    }

    /**
     * 处理属性初始化表达式
     *
     * @param fieldDeclarationNode
     * @param variableNode
     * @return
     */
    private ASTNode parseInitialExpression(FieldDeclarationASTNode fieldDeclarationNode, VariableASTNode variableNode) throws ParseException {
        if (tokens.getCurrentToken(fieldDeclarationNode).getType() == TokenType.IDENTIFIER) {
            // 检查是否是变量引用，还是函数调用
            if (tokens.catNextTokenNoComments().getType() == TokenType.LEFT_PAREN) {
                return null;
//                return parseFunctionCall(currentToken.getValue());
            } else {
                Token token = consumeToken(TokenType.IDENTIFIER);
                return new ASTNode(ASTNodeType.VARIABLE, token);
            }
        } else if (tokens.getCurrentToken(fieldDeclarationNode).getType() == TokenType.INTEGER_LITERAL) {
            Token token = consumeToken(TokenType.INTEGER_LITERAL);
            return new ASTNode(ASTNodeType.INTEGER_LITERAL, token);
        } else if (tokens.getCurrentToken(fieldDeclarationNode).getType() == TokenType.CHARACTER_LITERAL) {
            Token token = consumeToken(TokenType.CHARACTER_LITERAL);
            return new ASTNode(ASTNodeType.CHARACTER_LITERAL, token);
        } else if (tokens.getCurrentToken(fieldDeclarationNode).getType() == TokenType.STRING_LITERAL) {
            Token token = consumeToken(TokenType.STRING_LITERAL);
            return new ASTNode(ASTNodeType.STRING_LITERAL, token);
        } else if (tokens.getCurrentToken(fieldDeclarationNode).getType() == TokenType.BOOLEAN_LITERAL) {
            Token token = consumeToken(TokenType.BOOLEAN_LITERAL);
            return new ASTNode(ASTNodeType.BOOLEAN_LITERAL, token);
        } else if (tokens.getCurrentToken(fieldDeclarationNode).getType() == TokenType.DOUBLE_LITERAL) {
            Token token = consumeToken(TokenType.DOUBLE_LITERAL);
            return new ASTNode(ASTNodeType.DOUBLE_LITERAL, token);
        } else if (tokens.getCurrentToken(fieldDeclarationNode).getType() == TokenType.FLOAT_LITERAL) {
            Token token = consumeToken(TokenType.FLOAT_LITERAL);
            return new ASTNode(ASTNodeType.FLOAT_LITERAL, token);
        } else if (tokens.getCurrentToken(fieldDeclarationNode).getType() == TokenType.LONG_LITERAL) {
            Token token = consumeToken(TokenType.LONG_LITERAL);
            return new ASTNode(ASTNodeType.LONG_LITERAL, token);
        } else {
            throw new ParseException("Unexpected token: " + tokens.getCurrentToken(fieldDeclarationNode));
        }
    }


    /**
     * 语法解析方法定义
     * @param classDeclarationASTNode
     * @param modify
     * @param typeNode
     * @return
     */
    private ASTNode parseMethodDeclaration(ClassDeclarationASTNode classDeclarationASTNode, Modify modify, ASTNode typeNode) throws ParseException {
        MethodDeclarationASTNode methodDeclarationNode = new MethodDeclarationASTNode(ASTNodeType.METHOD_DECLARATION, tokens.getCurrentToken(classDeclarationASTNode), classDeclarationASTNode);
        methodDeclarationNode.setReturnType(typeNode);
        methodDeclarationNode.setModify(modify);

        //处理方法名
        if (tokens.getCurrentToken(methodDeclarationNode).getType() == TokenType.IDENTIFIER) {
            consumeToken(TokenType.IDENTIFIER);
        }
        //处理方法参数列表
        if (tokens.getCurrentToken(methodDeclarationNode).getType() == TokenType.LEFT_PAREN) {
            consumeToken(TokenType.LEFT_PAREN);
        }
        ASTNode parameterList = null;
        while (true){
            if (tokens.getCurrentToken(methodDeclarationNode).getType() == TokenType.RIGHT_PAREN) {
               break;
            } else if (tokens.getCurrentToken(methodDeclarationNode).getType() == TokenType.IDENTIFIER) {
                if(parameterList != null){
                    parameterList = new ASTNode(ASTNodeType.PARAMETER_LIST, tokens.getCurrentToken(methodDeclarationNode), methodDeclarationNode);
                }
                DeclarationParamsASTNode declarationParamsASTNode = new DeclarationParamsASTNode(ASTNodeType.IDENTIFIER, tokens.getCurrentToken(methodDeclarationNode), parameterList);
                declarationParamsASTNode.setDeclarationParamsASTNodeType(new ASTNode(ASTNodeType.IDENTIFIER, tokens.getCurrentToken(methodDeclarationNode)));
                consumeToken(TokenType.IDENTIFIER);
                if (tokens.getCurrentToken(methodDeclarationNode).getType() == TokenType.IDENTIFIER) {
                    declarationParamsASTNode.setDeclarationParamsASTNodeValue(new ASTNode(ASTNodeType.IDENTIFIER, tokens.getCurrentToken(methodDeclarationNode)));
                    parameterList.addChild(declarationParamsASTNode);
                    consumeToken(TokenType.IDENTIFIER);
                }else {
                    throw new ParseException("Unexpected token: " + tokens.getCurrentToken(methodDeclarationNode).getValue());
                }
            }
        }
        //添加参数列表
        methodDeclarationNode.setParameterList(parameterList);
        //)
        consumeToken(TokenType.RIGHT_PAREN);

        //处理throws声明抛出的异常
        if (tokens.getCurrentToken(methodDeclarationNode).getType() == TokenType.THROWS){
            ASTNode throwsNode = new ASTNode(ASTNodeType.THROWS, tokens.getCurrentToken(methodDeclarationNode), methodDeclarationNode);
            consumeToken(TokenType.THROWS);
            while (tokens.getCurrentToken(methodDeclarationNode).getType() != TokenType.LEFT_BRACE) {
                //处理public void demo () 'throws Exception'{}
                break;

            }
        }

        //处理方法体 block {
        consumeToken(TokenType.LEFT_BRACE);

        ASTNode methodBodyNode = new ASTNode(ASTNodeType.BLOCK);

        // 解析方法体中的语句，直到匹配到结束符号“}”
        while (tokens.getCurrentToken(methodDeclarationNode).getType() != TokenType.RIGHT_BRACE) {
            // 解析当前语句，并将其添加到方法体的语法树节点中
//            ASTNode statementNode = parseStatement();
//            methodBodyNode.addChild(statementNode);
            break;
        }



        return null;
    }


    private ASTNode parseType() throws ParseException {
        Token token = tokens.getCurrentToken();
        ASTNode typeNode = null;
        switch (token.getType()) {
            case IDENTIFIER:
                typeNode = new ASTNode(ASTNodeType.IDENTIFIER, token);
                consumeToken(TokenType.IDENTIFIER);
                break;
            case BYTE:
                consumeToken(TokenType.BYTE);
                typeNode = new ASTNode(ASTNodeType.PRIMITIVE_TYPE, token);
                break;
            case BOOLEAN:
                consumeToken(TokenType.BOOLEAN);
                typeNode = new ASTNode(ASTNodeType.PRIMITIVE_TYPE, token);
                break;
            case CHAR:
                consumeToken(TokenType.CHAR);
                typeNode = new ASTNode(ASTNodeType.PRIMITIVE_TYPE, token);
                break;
            case INT:
                consumeToken(TokenType.INT);
                typeNode = new ASTNode(ASTNodeType.PRIMITIVE_TYPE, token);
                break;
            case LONG:
                consumeToken(TokenType.LONG);
                typeNode = new ASTNode(ASTNodeType.PRIMITIVE_TYPE, token);
                break;
            case FLOAT:
                consumeToken(TokenType.FLOAT);
                typeNode = new ASTNode(ASTNodeType.PRIMITIVE_TYPE, token);
                break;
            case SHORT:
                consumeToken(TokenType.SHORT);
                typeNode = new ASTNode(ASTNodeType.PRIMITIVE_TYPE, token);
                break;
            case VOID:
                typeNode = new ASTNode(ASTNodeType.VOID);
                consumeToken(TokenType.VOID);
                break;
            default:
                throw new ParseException("Unexpected token: " + token.getValue());
        }
        if (typeNode != null && tokens.getCurrentToken().getValue().equals("[")) {
            typeNode = parseArrayType(typeNode);
        }
        return typeNode;
    }

    private ASTNode parseArrayType(ASTNode elementTypeNode) throws ParseException {
        consumeToken(TokenType.LEFT_BRACKET);
        consumeToken(TokenType.RIGHT_BRACKET);
        ASTNode arrayTypeNode = new ASTNode(ASTNodeType.ARRAY_TYPE);
        arrayTypeNode.addChild(elementTypeNode);
        if (tokens.getCurrentToken().getValue().equals("[")) {
            arrayTypeNode = parseArrayType(arrayTypeNode);
        }
        return arrayTypeNode;
    }


    private ASTNode parsePackageDeclaration() throws ParseException {
        // 包名
        String packageName = "";
        // 包声明节点
        PackageDeclarationASTNode packageDeclaration = new PackageDeclarationASTNode(ASTNodeType.PACKAGE_DECLARATION);
        // 包关键字
        consumeToken(TokenType.PACKAGE);
        // 解析包名
        while (tokens.getCurrentToken(packageDeclaration).getType() == TokenType.IDENTIFIER) {
            Token token = tokens.getCurrentToken();
            consumeToken(TokenType.IDENTIFIER);
            packageName += token.getValue();
            if (tokens.getCurrentToken(packageDeclaration).getType() == TokenType.DOT) {
                packageName += ".";
                consumeToken(TokenType.DOT);
            }
        }
        // 设置包名属性
        packageDeclaration.setName(packageName);
        // 结束符号
        consumeToken(TokenType.SEMICOLON);
        return packageDeclaration;
    }

    private ASTNode parseImportDeclaration() throws ParseException {
        // 导入语句节点
        ImportDeclarationASTNode importDeclaration = new ImportDeclarationASTNode(ASTNodeType.IMPORT_DECLARATION);
        // import 关键字
        consumeToken(TokenType.IMPORT);
        // 解析导入的包名
        String packageName = "";
        while (tokens.getCurrentToken(importDeclaration).getType() == TokenType.IDENTIFIER
                || tokens.getCurrentToken(importDeclaration).getType() == TokenType.DOT) {
            if (tokens.getCurrentToken(importDeclaration).getType() == TokenType.IDENTIFIER) {
                packageName += tokens.getCurrentToken().getValue();
                consumeToken(TokenType.IDENTIFIER);
            } else {
                consumeToken(TokenType.DOT);
                packageName += ".";
            }
        }
        // 设置导入的包名属性
        importDeclaration.setName(packageName);
        // 结束符号
        consumeToken(TokenType.SEMICOLON);
        return importDeclaration;
    }


    private ASTNode parseExpression(FieldDeclarationASTNode fieldDeclarationNode, VariableASTNode leftVariableNode, TokenType expressionType) {
        switch (expressionType) {
            case EQUAL:
        }


        return null;
    }

//    private ASTNode parsePrimaryExpression() throws ParseException {
//        Token currentToken = tokens.getCurrentToken();
//
//    }

    private Token consumeToken(TokenType expectedType) throws ParseException {
        Token currentToken = tokens.getCurrentToken();
        if (currentToken.getType() != expectedType) {
            throw new ParseException("Unexpected token: " + currentToken.getValue());
        }
        tokens.forwardToken();
        return currentToken;
    }
}